package com.ctg.itrdc.imageconsole.service.deploy;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;

import javax.annotation.Resource;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.ctg.itrdc.imageconsole.common.util.PropertiesUtils;
import com.ctg.itrdc.imageconsole.common.util.TimeUtils;
import com.ctg.itrdc.imageconsole.data.dao.IAutoscalePolicyDao;
import com.ctg.itrdc.imageconsole.data.dao.IClusterConfigDao;
import com.ctg.itrdc.imageconsole.data.dao.IDockerImageTagDao;
import com.ctg.itrdc.imageconsole.data.dao.IDockerMicroAppDao;
import com.ctg.itrdc.imageconsole.data.dao.IDockerMicroGroupDao;
import com.ctg.itrdc.imageconsole.data.dao.IDockerMicroGroupDetailDao;
import com.ctg.itrdc.imageconsole.data.dao.IDockerMicroServiceDao;
import com.ctg.itrdc.imageconsole.data.dao.ISystemNoticeDao;
import com.ctg.itrdc.imageconsole.data.dto.DmsAppDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsAppServicesDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsFixedJsonDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsServiceDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsVolumeDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsVolumeLogDTO;
import com.ctg.itrdc.imageconsole.data.dto.K8sNamespaceDTO;
import com.ctg.itrdc.imageconsole.data.dto.KeyValueDTO;
import com.ctg.itrdc.imageconsole.data.entity.AutoscalePolicy;
import com.ctg.itrdc.imageconsole.data.entity.DockerMicroApp;
import com.ctg.itrdc.imageconsole.data.entity.DockerMicroService;
import com.ctg.itrdc.imageconsole.service.IAutoElasticService;
import com.ctg.itrdc.imageconsole.service.IK8sNamespaceService;
import com.ctg.itrdc.imageconsole.util.KubeUtils;
import com.ctg.itrdc.pasp.security.utils.WebUtils;
import com.ctg.itrdc.paspsdk.common.entity.PageInfo;

import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.HostPathVolumeSource;
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.LabelSelector;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.PodSpec;
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.api.model.ResourceRequirements;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.extensions.Deployment;
import io.fabric8.kubernetes.api.model.extensions.DeploymentSpec;
import io.fabric8.kubernetes.api.model.extensions.DeploymentStrategy;
import io.fabric8.kubernetes.api.model.extensions.RollingUpdateDeployment;


@Component("appManagerService")
public class AppManagerService {
	
	
	private static String configProperties = "config.properties";
	
	@Resource
	AppManagerServiceAux appManagerServiceAux;
	
	@Resource
	IDockerMicroAppDao appDao;	
	
	@Resource
	IDockerMicroServiceDao serviceDao;
	
	@Resource
	IAutoscalePolicyDao autoscalePolicyDao;
	
	@Resource
	IDockerImageTagDao imageTagDao;
	
	@Resource
	IClusterConfigDao clusterConfigDao;	
	
	@Resource 
	IDockerMicroGroupDao groupDao;
	
	@Resource 
	IDockerMicroGroupDetailDao groupDetailDao;
	
	@Resource
	IAutoElasticService autoElasticService;
	
	@Resource
	ISystemNoticeDao noticeDao;
	
	@Resource
	private IK8sNamespaceService k8sNamespaceService;
	
	
	public boolean appCodeExist(Long userId, String namespace, String appCode) 
	{		
		DockerMicroApp app = new DockerMicroApp();
		app.setCreateUserId(userId);
		app.setNamespace(namespace);
		app.setCode(appCode);
		List<DockerMicroApp> appList = appDao.selectByExample(app);
		return 0 != appList.size();	
	}

	public boolean serviceCodeExist(Long appId, String serviceCode) 
	{		
		Long userId = WebUtils.getCtgUser().getSysUserId();
		List<DockerMicroService> serviceList = serviceDao.selectByCreateUserIdAndAppIdAndServiceCode(userId, appId, serviceCode);
		return 0 != serviceList.size();		
	}
	
	
	public Object newFixedJson(DmsFixedJsonDTO fixedJson)
	{
		String logHostPath = "log.hostPath";
		String hostPath = PropertiesUtils.getConfigValueCache(configProperties, logHostPath);
		if(null == hostPath)
			throw new RuntimeException(String.format("% is not found in %", logHostPath, configProperties));
		
		String deploymentRevisionHistoryLimit = "deployment.revisionHistoryLimit";
		String revisionHistoryLimit = PropertiesUtils.getConfigValueCache(configProperties, deploymentRevisionHistoryLimit);
		if(null == revisionHistoryLimit)
			throw new RuntimeException(String.format("% is not found in %", deploymentRevisionHistoryLimit, configProperties));
		
		String harborVip = "harbor.vip";
		String registry = PropertiesUtils.getConfigValueCache(configProperties, harborVip);
		if(null == registry)
			throw new RuntimeException(String.format("% is not found in %", harborVip, configProperties));
		
		fixedJson.setNamespace(fixedJson.getNamespace());	
				
		String imageRoutine = String.format("%s/%s:%s", registry, fixedJson.getImageName(), fixedJson.getTag());
	 	
		String dpName = "$dpName";
		Deployment dp = new Deployment();
		dp.setApiVersion("extensions/v1beta1");		
		dp.setMetadata(new ObjectMeta());
		dp.getMetadata().setName(dpName);
		dp.getMetadata().setNamespace(fixedJson.getNamespace());		
		dp.setSpec(new DeploymentSpec());
		dp.getSpec().setReplicas(fixedJson.getReplicas().intValue()); 
		dp.getSpec().setSelector(new LabelSelector());
		dp.getSpec().getSelector().setMatchLabels(new HashMap<String, String>());
		dp.getSpec().getSelector().getMatchLabels().put("name", dpName);
		dp.getSpec().setStrategy(new DeploymentStrategy());
		dp.getSpec().getStrategy().setType("RollingUpdate");
		dp.getSpec().getStrategy().setRollingUpdate(new RollingUpdateDeployment());
		dp.getSpec().getStrategy().getRollingUpdate().setMaxSurge(new IntOrString(1));
		dp.getSpec().getStrategy().getRollingUpdate().setMaxUnavailable(new IntOrString(0));
		dp.getSpec().setRevisionHistoryLimit(new Integer(revisionHistoryLimit));
		dp.getSpec().setTemplate(new PodTemplateSpec());
		dp.getSpec().getTemplate().setMetadata(new ObjectMeta());
		dp.getSpec().getTemplate().getMetadata().setLabels(new HashMap<String, String>());		
		dp.getSpec().getTemplate().getMetadata().getLabels().put("name", dpName);		
		dp.getSpec().getTemplate().getMetadata().getLabels().put("servicename", "$lvsServiceName");		
		dp.getSpec().getTemplate().getMetadata().getLabels().put("source", "console");
		if (StringUtils.isEmpty(fixedJson.getServicePort())) {
			String servicePort = PropertiesUtils.getConfigValueCache(configProperties, "servicePort");
			dp.getSpec().getTemplate().getMetadata().getLabels().put("serviceport", servicePort);
		} else {
			dp.getSpec().getTemplate().getMetadata().getLabels().put("serviceport", fixedJson.getServicePort());
		}
//		dp.getSpec().getTemplate().getMetadata().getLabels().put("image", String.format("%d-%d", fixedJson.getImageName(), fixedJson.getTag()));
		dp.getSpec().getTemplate().setSpec(new PodSpec());
		dp.getSpec().getTemplate().getSpec().setContainers(new ArrayList<Container>());
		dp.getSpec().getTemplate().getSpec().getContainers().add(new Container());
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setName(dpName);
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(imageRoutine);	
		
		// envs
		if(null != fixedJson.getEnvs()) {
			dp.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(new ArrayList<EnvVar>());
			
			List<KeyValueDTO> envs = fixedJson.getEnvs();
			for(KeyValueDTO env : envs) 
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().add(new EnvVar(env.getKey(), env.getValue(), null));
							
		}
		else
			dp.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(null);
			
		String cpuRequest = null;
		String memoryRequest = null;
		if (StringUtils.isNotEmpty(fixedJson.getCpuRequest())) {
			cpuRequest = fixedJson.getCpuRequest();
		} else {
			cpuRequest = PropertiesUtils.getConfigValueCache(configProperties, "cpu.request");
		}
		if (StringUtils.isNotEmpty(fixedJson.getMemoryRequest())) {
			memoryRequest = fixedJson.getMemoryRequest();
		} else {
			memoryRequest = PropertiesUtils.getConfigValueCache(configProperties, "memory.request") + "M";
		}
		// resources.requests
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setResources(new ResourceRequirements());
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().setRequests(new HashMap<String, Quantity>());
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getRequests().put("cpu", new Quantity(cpuRequest));
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getRequests().put("memory", new Quantity(memoryRequest));
		// resources.limits
		if(null != fixedJson.getCpuLimit() || null != fixedJson.getMemoryLimit())
		{			
			dp.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().setLimits(new HashMap<String, Quantity>());
		}			
		if(null != fixedJson.getCpuLimit())
		{
			Quantity cpuQ = new Quantity(fixedJson.getCpuLimit());
			dp.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getLimits().put("cpu", cpuQ);
		}			
		if(null != fixedJson.getMemoryLimit())
		{
			Quantity memoryQ = new Quantity(fixedJson.getMemoryLimit() + "M");
			dp.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getLimits().put("memory", memoryQ);
		}			
		
		// nodeSelector
		List<String> groupCodeList = fixedJson.getGroupCodeList();
		if(null != groupCodeList && groupCodeList.size() != 0)
		{
			dp.getSpec().getTemplate().getSpec().setNodeSelector(new HashMap<String, String>());			
			for(String groupCode : groupCodeList)
			{			
				String keyValue = groupCode;				
				dp.getSpec().getTemplate().getSpec().getNodeSelector().put(keyValue, keyValue);
			}
		}
		
		// volumes
		List<DmsVolumeDTO> volumeList = fixedJson.getVolumeList();
		List<DmsVolumeLogDTO> logList = fixedJson.getVolumeLogList();
		if((null != volumeList && volumeList.size() != 0) || (null != logList && logList.size() != 0)) {
				dp.getSpec().getTemplate().getSpec().setVolumes(new ArrayList<Volume>());
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).setVolumeMounts(new ArrayList<VolumeMount>());
		}		
		else {
			dp.getSpec().getTemplate().getSpec().setVolumes(null);
			dp.getSpec().getTemplate().getSpec().getContainers().get(0).setVolumeMounts(null);
		}
		
		if(null != volumeList && volumeList.size() != 0) {			
			// volumes
			for(int i = 0; i < volumeList.size(); i++)
			{
				dp.getSpec().getTemplate().getSpec().getVolumes().add(new Volume());
				dp.getSpec().getTemplate().getSpec().getVolumes().get(i).setName(volumeList.get(i).getName());
				dp.getSpec().getTemplate().getSpec().getVolumes().get(i).setHostPath(new HostPathVolumeSource());
				dp.getSpec().getTemplate().getSpec().getVolumes().get(i).getHostPath().setPath(volumeList.get(i).getHostPath());
			}						
			for(int i = 0; i < volumeList.size(); i++)
			{				
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().add(new VolumeMount());
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().get(i).setName(volumeList.get(i).getName());
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().get(i).setMountPath(volumeList.get(i).getMountPath());
			}			
		}
		if(null != logList && logList.size() != 0) {
			// logs
			int volumeSize = null == volumeList ? 0 : volumeList.size();
			for(int i = 0; i < logList.size(); i++)
			{
				dp.getSpec().getTemplate().getSpec().getVolumes().add(new Volume());
				dp.getSpec().getTemplate().getSpec().getVolumes().get(i + volumeSize).setName(logList.get(i).getName());
				dp.getSpec().getTemplate().getSpec().getVolumes().get(i + volumeSize).setHostPath(new HostPathVolumeSource());
				dp.getSpec().getTemplate().getSpec().getVolumes().get(i + volumeSize).getHostPath().setPath(hostPath);
			}							
			for(int i = 0; i < logList.size(); i++)
			{				
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().add(new VolumeMount());
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().get(i + volumeSize).setName(logList.get(i).getName());
				dp.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().get(i + volumeSize).setMountPath(logList.get(i).getPath());
			}
		}
		
		// set null
		dp.getMetadata().setFinalizers(null);
		dp.getMetadata().setOwnerReferences(null);
		dp.getSpec().getSelector().setMatchExpressions(null);
		dp.getSpec().getTemplate().getMetadata().setFinalizers(null);
		dp.getSpec().getTemplate().getMetadata().setOwnerReferences(null);
		dp.getSpec().getTemplate().getSpec().setImagePullSecrets(null);		
//		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(null);
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setArgs(null);
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setCommand(null);
		dp.getSpec().getTemplate().getSpec().getContainers().get(0).setPorts(null);
		
		
		return dp;	
	}

	
	
	public Long createApp(DmsAppServicesDTO appServicesDTO)
	{		
		DmsAppDTO appDTO = appServicesDTO.getApp();		
		
		// insert to docker_micro_app
		DockerMicroApp app = new DockerMicroApp();		
		app.setK8sCode(appServicesDTO.getServices().get(0).getK8sCode());
		app.setNamespace(appServicesDTO.getApp().getNamespace());
		app.setCode(appDTO.getAppCode());
		app.setName(appDTO.getAppName());
		app.setDescription(appDTO.getDescription());
		app.setCreateUserId(com.ctg.itrdc.pasp.security.utils.WebUtils.getCtgUser().getSysUserId());		
		app.setCreateTime(TimeUtils.getNowDateStr());
		app.setLastUpdateUserId(app.getCreateUserId());
		app.setLastUpdateTime(app.getCreateTime());		
		Long appId = appDao.insert(app);
		
		appDTO.setAppId(appId);
		for(int i = 0; i < appServicesDTO.getServices().size(); i++) {	
			// one service failed, others continue
			try {
				DmsServiceDTO serviceDTO = appServicesDTO.getServices().get(i);
				this.createService(appDTO, serviceDTO);
			} catch (Exception e) {
				
			}			
		}	
		
		return appId;
	}	
	
	public void deleteApp(Long appId) 
	{		
		DockerMicroApp app = appDao.selectById(appId);
		if(null == app)
			return;
		List<DockerMicroService> serviceList = serviceDao.selectByDockerMicroAppId(appId);
		for(DockerMicroService service : serviceList)		
			this.deleteService(service.getId());			
		
		// delete the app record
		appDao.deleteByPrimaryKey(app);
	}
	
	/*
	 * @Parameter appServiceVersionDTO.getApp().getAppId()
	 * @Parameter appServiceVersionDTO.getService().getServiceCode()
	 * @Parameter appServiceVersionDTO.getVersion()
	 */
	public Long createService(DmsAppDTO appDTO, DmsServiceDTO serviceDTO)
	{			
		// insert autoscalePolicy
		Long autoscalePolicyId = null;
		final AutoscalePolicy autoscalePolicy = new AutoscalePolicy();
		if(1 == serviceDTO.getIsAutoscalable().intValue()) {			
			autoscalePolicy.setElasticIndicator(serviceDTO.getElasticIndicator());
			autoscalePolicy.setMinPodNum(serviceDTO.getMinPodNum());
			autoscalePolicy.setMaxPodNum(serviceDTO.getMaxPodNum());
			autoscalePolicy.setMaxCpu(serviceDTO.getMaxCpu());
			autoscalePolicy.setElasticStartTime(serviceDTO.getElasticStartTime());
			autoscalePolicy.setElasticEndTime(serviceDTO.getElasticEndTime());
			autoscalePolicy.setTimeRate(serviceDTO.getTimeRate());
			autoscalePolicyId = autoscalePolicyDao.insert(autoscalePolicy);
		}		
		if(null == appDTO.getAppCode()) {
			DockerMicroApp app = appDao.selectById(appDTO.getAppId());
			appDTO.setAppCode(app.getCode());
		}
		String lowerCasedDpName = String.format("%d-%s-%s", WebUtils.getCtgUser().getSysUserId(), appDTO.getAppCode(), serviceDTO.getServiceCode()).toLowerCase();
		String lvsServiceName = String.format("%d-%s-%s", WebUtils.getCtgUser().getSysUserId(), appDTO.getAppCode(), serviceDTO.getServiceCode());
		String yamlContent = serviceDTO.getYamlContent().replace("$dpName", lowerCasedDpName).replace("$lvsServiceName", lvsServiceName);
		
		final DockerMicroService service = new DockerMicroService();
		service.setDockerMicroAppId(appDTO.getAppId());
		service.setDockerImageIndexId(serviceDTO.getImageIndexId());
		service.setCode(serviceDTO.getServiceCode());
		service.setDpName(lowerCasedDpName);
		service.setServicePort(serviceDTO.getServicePort());
		service.setUrl(serviceDTO.getUrl());
		service.setExternalPort(serviceDTO.getExternalPort());
		service.setLvsServiceName(lvsServiceName);
		service.setYamlContent(yamlContent);
		service.setReplicas(serviceDTO.getReplicas());
		
		service.setIsAutoScalable(serviceDTO.getIsAutoscalable());
		service.setAutoscalePolicyId(autoscalePolicyId);
		service.setK8sCode(serviceDTO.getK8sCode());
		service.setNamespace(appDTO.getNamespace());
		service.setCreateUserId(WebUtils.getCtgUser().getSysUserId());
		service.setCreateTime(TimeUtils.getNowDateStr());
		service.setLastUpdateUserId(service.getCreateUserId());
		service.setLastUpdateTime(service.getCreateTime());		
		Long serviceId = null;
		final String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(service.getK8sCode());
		
		// 调用分布式web的生成Nginx配置的接口
		if(StringUtils.isNotEmpty(service.getUrl())) 
			Executors.newSingleThreadExecutor().submit(new Runnable() {				
				@Override
				public void run() {
					appManagerServiceAux.callLvs(service.getK8sCode(), service.getUrl(), service.getExternalPort(), service.getLvsServiceName());						
				}
			});
		// autoscaler			
		if(1 == service.getIsAutoscalable().intValue())
			Executors.newSingleThreadExecutor().submit(new Runnable() {				
				@Override
				public void run() {
					autoElasticService.startAutoElastic(apiServerUrl, service.getNamespace(), service.getDpName(),
							autoscalePolicy, service.getCreateUserId());						
				}
			});
		
		try	{				
			if(null == apiServerUrl)
				throw new RuntimeException("Error : selecting api_server_url by cluster_code returns null");
			KubeUtils.createDp(apiServerUrl, service.getNamespace(), service.getYamlContent());				
			service.setState("001");	// online
			service.setReleaseState("002");		// success state	
			serviceId = serviceDao.insert(service);
		} catch(Exception e) {			
			service.setState("002");		// offline
			service.setReleaseState("003");		// failure state
			service.setReleaseStateDescription(e.getMessage());
			serviceDao.insert(service);
			throw new RuntimeException(e.getMessage());
		}				
		
		return serviceId;
	}		
	
	public void terminateService(Long serviceId)	
	{		
		final DockerMicroService service = serviceDao.selectById(serviceId);
		if(null == service)
			return;		
		final String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(service.getK8sCode());
				
		if(1 == service.getIsAutoscalable().intValue()) {			
			service.setIsAutoScalable(0);
			final AutoscalePolicy autoscalePolicy = autoscalePolicyDao.selectById(service.getAutoscalePolicyId());
			Executors.newSingleThreadExecutor().submit(new Runnable() {				
				@Override
				public void run() {
					autoElasticService.stopAutoElastic(apiServerUrl, service.getNamespace(), service.getDpName(), 
							autoscalePolicy, service.getCreateUserId());					
				}
			});
		}
		
		service.setState("002");
		service.setReleaseState("002");
		service.setLastUpdateTime(TimeUtils.getNowDateStr());		
		serviceDao.updateSelectiveByPrimaryKey(service);
		
		// scale rc to 0 and set offline
		try {						
			KubeUtils.scaleDp(apiServerUrl, service.getNamespace(), service.getDpName(), 0);					
		} catch (Exception e) {
			
		}	
		
	}
	
	public void startService(Long serviceId)
	{		
		DockerMicroService service = serviceDao.selectById(serviceId);
		if(null == service)
			throw new NullPointerException("Error : selecting docker_micro_service by id returns null");
				
		// start this service	
		String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(service.getK8sCode());
		try {
			if(!KubeUtils.dpExist(apiServerUrl, service.getNamespace(), service.getDpName()))
				KubeUtils.createDp(apiServerUrl, service.getNamespace(), service.getYamlContent());
			KubeUtils.scaleDp(apiServerUrl, service.getNamespace(), service.getDpName(), service.getReplicas());
		} catch(Exception e) {
			serviceDao.updateStateAndReleaseStateAndDesc(serviceId, "002", "003", e.getMessage(), TimeUtils.getNowDateStr());
			throw new RuntimeException(e.getMessage());
		}						
		serviceDao.updateStateAndReleaseStateAndDesc(serviceId, "001", "002", null, TimeUtils.getNowDateStr());
			
	}		
	
	public void deleteService(Long serviceId) 
	{
		final DockerMicroService service = serviceDao.selectById(serviceId);				
		if(null == service)
			return;	
		
		final String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(service.getK8sCode());		
		
		if(1 == service.getIsAutoscalable().intValue())	{
			final AutoscalePolicy autoscalePolicy = autoscalePolicyDao.selectById(service.getAutoscalePolicyId());
			Executors.newSingleThreadExecutor().submit(new Runnable() {				
				@Override
				public void run() {
					autoElasticService.stopAutoElastic(apiServerUrl, service.getNamespace(), service.getDpName(), 
							autoscalePolicy, service.getCreateUserId());					
				}
			});
		}
		// 由于旧版本使用的是rc发布应用，所以此处需兼容rc的情况。那么rc发布时，有个特点，就是使用的都是default命名空间
		if ("default".equals(service.getNamespace())) {
			KubeUtils.deleteRC(apiServerUrl, service.getNamespace(), service.getDpName());
		} else {
			KubeUtils.deleteDp(apiServerUrl, service.getNamespace(), service.getDpName()); 
		}
		
		// delete the service record
		serviceDao.deleteByPrimaryKey(service);	
		
		// delete the autoscalePolicy record
		if(null != service.getAutoscalePolicyId())
			autoscalePolicyDao.deleteById(service.getAutoscalePolicyId());
		
	}

	public void replaceService(DmsServiceDTO serviceDTO) {
		DockerMicroService service = serviceDao.selectById(serviceDTO.getServiceId());
		if(null == service)
			throw new RuntimeException("Error : selecting docker_micro_service by id returns null");
		String yamlContent = serviceDTO.getYamlContent().replace("$dpName", service.getDpName()).replace("$lvsServiceName", service.getLvsServiceName());
		service.setReplicas(serviceDTO.getReplicas());
		service.setYamlContent(yamlContent);
		serviceDao.updateSelectiveByPrimaryKey(service);
		String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(service.getK8sCode());
		KubeUtils.replaceDp(apiServerUrl, service.getNamespace(), service.getDpName(), yamlContent);
	}
	

	public void rollbackService(Long serviceId, Integer versionId) {
		DockerMicroService service = serviceDao.selectById(serviceId);
		if(null == service)
			throw new RuntimeException("Error : selecting docker_micro_service by id returns null");
		String monitorEndpoint = clusterConfigDao.selectMonitorUrlByClusterCode(service.getK8sCode());
		String rolloutUrlTemplate = "http://{0}/api/v1/{1}/deployment/{2}/{3}/rollout";
		String rolloutUrl = MessageFormat.format(rolloutUrlTemplate, monitorEndpoint, service.getK8sCode(), service.getNamespace(), service.getDpName());
		HashMap<String, String> body = new HashMap<String, String>();
		body.put("revison", versionId.toString());
		WebTarget target = ClientBuilder.newClient().target(rolloutUrl);
		Response response = target.request().post(Entity.entity(body, MediaType.APPLICATION_JSON_TYPE));
		if(null == response)
			throw new RuntimeException(String.format("Error : call rollback in %s has no reposonse", monitorEndpoint));
		if(response.getStatus() >= 300)
			throw new RuntimeException(String.format("Error : call rollback in %s returns %d", monitorEndpoint, response.getStatus()));
	}
	
	public void configAutoScaler(DmsServiceDTO serviceDTO) {
		DockerMicroService service = serviceDao.selectById(serviceDTO.getServiceId());
		if(null == service)
			throw new RuntimeException("Error : selecting docker_micro_service by id returns null");
		Integer oldIsAutoscalable = service.getIsAutoscalable();
		Long autoscalePolicyId = service.getAutoscalePolicyId();		
		
		AutoscalePolicy autoscalePolicy = new AutoscalePolicy();
		autoscalePolicy.setId(autoscalePolicyId);
		autoscalePolicy.setElasticIndicator(serviceDTO.getElasticIndicator());
		autoscalePolicy.setMinPodNum(serviceDTO.getMinPodNum());
		autoscalePolicy.setMaxPodNum(serviceDTO.getMaxPodNum());
		autoscalePolicy.setMaxCpu(serviceDTO.getMaxCpu());
		autoscalePolicy.setElasticStartTime(serviceDTO.getElasticStartTime());
		autoscalePolicy.setElasticEndTime(serviceDTO.getElasticEndTime());
		autoscalePolicy.setTimeRate(serviceDTO.getTimeRate());		
		
		String apiServerUrl = clusterConfigDao.selectApiServerUrlByClusterCode(service.getK8sCode());
		
		if(1 == oldIsAutoscalable.intValue()) {		// autoscalable before
			if(1 == serviceDTO.getIsAutoscalable().intValue()) {
				autoscalePolicyDao.updateByPrimaryKey(autoscalePolicy);
				autoElasticService.modifyAutoElastic(apiServerUrl, service.getNamespace(), service.getDpName(),
						autoscalePolicy, service.getCreateUserId());
			}				
			else {
				serviceDao.updateIsAutoscalableAndAutoscalePolicyId(service.getId(), 0, null);
				autoElasticService.stopAutoElastic(apiServerUrl, service.getNamespace(), service.getDpName(),
						autoscalePolicy, service.getCreateUserId());
			}
				
		}
		else {		// not autoscalable before
			if(null == autoscalePolicyId)  // no autoscalePolicy record yet		
				autoscalePolicyId = autoscalePolicyDao.insert(autoscalePolicy);			
					
			serviceDao.updateIsAutoscalableAndAutoscalePolicyId(service.getId(), 1, autoscalePolicyId);
			autoElasticService.startAutoElastic(apiServerUrl, service.getNamespace(), service.getDpName(), 
					autoscalePolicy, service.getCreateUserId());
		}
	}
	
	public void configLvs(Long serviceId, String url, String externalPort) {
		
		
		if(null == externalPort || externalPort.isEmpty())
			externalPort = PropertiesUtils.getConfigValueCache("config.properties", "deployment.externalPort");
		if(null == externalPort)
			throw new RuntimeException(String.format("%s is not configured in %", "deployment.externalPort", "config.properties"));
		
		DockerMicroService service = serviceDao.selectById(serviceId);		
		service.setUrl(url);
		service.setExternalPort(externalPort);
		serviceDao.updateSelectiveByPrimaryKey(service);		
		appManagerServiceAux.callLvs(service.getK8sCode(), url, externalPort, service.getLvsServiceName());
	}
	
	// 判断设置的cpu和memory是否超过当前租户剩下的
	public String checkCpuAndMemory(List<DmsFixedJsonDTO> fixedJsonList){
		double cpuTotalBySet = 0;
		long memoryTotalBySet = 0l;
		Integer replicasTotalBySet = 0;
		
		for(DmsFixedJsonDTO fixedJson : fixedJsonList){
			cpuTotalBySet = cpuTotalBySet + Double.valueOf(fixedJson.getCpuLimit()) * fixedJson.getReplicas();
			memoryTotalBySet = memoryTotalBySet + Integer.valueOf(fixedJson.getMemoryLimit()) * fixedJson.getReplicas();
			replicasTotalBySet = replicasTotalBySet + fixedJson.getReplicas();
		}
		if (cpuTotalBySet == 0 && memoryTotalBySet == 0) {
			return null;
		}
		K8sNamespaceDTO namespaceDTO = new K8sNamespaceDTO();
		namespaceDTO.setClusterCode(fixedJsonList.get(0).getClusterCode());
		namespaceDTO.setNamespaceCode(fixedJsonList.get(0).getNamespace());
		namespaceDTO.setCreateUserId(WebUtils.getCtgUser().getSysUserId());
		
		PageInfo<K8sNamespaceDTO> pageInfo = k8sNamespaceService.queryNamespaceList(namespaceDTO, 1, 1);
		// 该租户下限制的总共cpu
		double cpuQuota = Double.valueOf(pageInfo.getList().get(0).getCpuQuota());
		// 该租户下限制的总共memory
		long memoryQuota = Long.valueOf(pageInfo.getList().get(0).getMemoryQuota());
		// 该租户下限制的总共容器数
		Integer podQuota = pageInfo.getList().get(0).getPodQuota();
		// 当前已使用cpu
		String usedCpu = pageInfo.getList().get(0).getUsedCpu();
		int usedCpuInt = 0;
		if (usedCpu.endsWith("m")) {
			usedCpu = usedCpu.substring(0,usedCpu.indexOf("m"));
			usedCpuInt = Integer.valueOf(usedCpu);
		} else {
			usedCpuInt = Integer.valueOf(usedCpu) * 1000;
		}
	    // 当前已使用内存
		String usedMemory = pageInfo.getList().get(0).getUsedMemory();
		if (usedMemory.endsWith("M")){
			usedMemory = usedMemory.substring(0,usedMemory.indexOf("M"));
		}
		// 当前已使用的容器数
		Integer usedPod = Integer.valueOf(pageInfo.getList().get(0).getUsedPods());
		// 计算出剩下的cpu和内存和容器数
		double remainCpu = (cpuQuota * 1000 - usedCpuInt)/1000.0;
		long remainMemory = memoryQuota - Long.valueOf(usedMemory);
		Integer remainPod = podQuota - usedPod;
		if (replicasTotalBySet > remainPod) {
			return "所剩容器数不够！该" + fixedJsonList.get(0).getNamespace()+"租户当前还剩"+remainPod+"个容器数可用，"
					+ "您此次共配置了"+replicasTotalBySet+"个容器数";
		} else if (cpuTotalBySet > remainCpu) {
			return "所剩cpu不够！该" + fixedJsonList.get(0).getNamespace()+"租户当前还剩"+remainCpu+"核cpu，"
					+ "您此次共配置了"+cpuTotalBySet+"核cpu";
		} else if (memoryTotalBySet > remainMemory) {
			return "所剩内存不够！该"+fixedJsonList.get(0).getNamespace()+"租户当前还剩"+remainMemory+"MB内存，"
					+ "您此次共配置了"+memoryTotalBySet+"MB内存";
		} else {
			return null;
		}
	}

	
}
